using System;
//using System.Diagnostics;
using FlatRedBall;
using FlatRedBall.Graphics.Animation;
using FlatRedBall.Math.Geometry;
using Microsoft.Xna.Framework.Audio;

using Xzipit.Utilities;
using Xzipit.Interfaces;
using Xzipit.Utilities.Gestures;
using Microsoft.Xna.Framework;
using Xzipit.Utilities.Touch;
using FlatRedBall.Graphics;

namespace Xzipit.GameObjects
{
    class Velcro : Obstacle, IDraggable, IPullable
    {
        #region Fields

        private int _type;
        private GameGesture _lastDrag;
        private Circle _startCollision;
        private Circle _endCollision;
        private Polygon _touchCollision;

        private float _spriteRotation;

        private int _openTime;
        private double _startTime;
        private double _elapsedTime;

        private double _resetTime;

        private SoundEffect _openSound;
        private Text _timeText;

        private const float MAX_DISTANCE = 4.0f;

        #endregion

        #region Methods

        #region Constructors
        // Constructor
        public Velcro(string contentManagerName)
        {
            // The default constructor. Use only for test purposes.
            _contentManagerName = contentManagerName;
            _type = 1;

            Initialize(true);
        }

        public Velcro(string contentManagerName, float x, float y, int type, float rot)
        {
            // Takes parameters from a level file and sets them here.
            _contentManagerName = contentManagerName;
            _type = type;
            this.Position.X = x;
            this.Position.Y = y;
            this.Position.Z = 0.1f;
            _spriteRotation = rot;

            Initialize(true);
        }


        public Velcro(string contentManagerName, float x, float y, int type, 
                        float rot, int openTime)
        {
            // Takes parameters from a level file and sets them here.
            _contentManagerName = contentManagerName;
            _type = type;
            this.Position.X = x;
            this.Position.Y = y;
            this.Position.Z = 0.1f;
            _spriteRotation = rot;

            _openTime = openTime;

            Initialize(true);
        }

        #endregion

        #region Initialization
        protected override void Initialize(bool addToManagers)
        {
            if (addToManagers)
            {
                AddToManagers();
            }
        }

        private void InitializeAnimations()
        {
            // Loads the animation chain for when the velcro opens.
            AnimationChainList ani = new AnimationChainList();
            AnimationChain opening = new AnimationChain();
            AnimationChain closing = new AnimationChain();

            for (int i = 1; i <= 10; i++)
            {
                opening.Add(new AnimationFrame(@"Content/GameObjects/Obstacles/Velcro/" + i, 0.06f, "Global"));
            }
            opening.Name = "opening";

            ani.Add(opening);

            for (int i = 10; i >= 1; i--)
            {
                closing.Add(new AnimationFrame(@"Content/GameObjects/Obstacles/Velcro/" + i, 0.06f, "Global"));
            }

            ani.Add(closing);

            _sprite = SpriteManager.AddSprite(ani);
            _sprite.AttachTo(this, false);
            _sprite.CurrentChainName = "opening";
            _sprite.Animate = false;
            _sprite.CurrentFrameIndex = 0;
            _sprite.RelativeRotationZ = _spriteRotation;
        }

        public virtual void AddToManagers()
        {
            SpriteManager.AddPositionedObject(this);

            InitializeAnimations();
            float xScale = 0.8f;
            float yScale = 1.0f;
            base.AddToManagers(xScale, yScale);

            // Creates collision circles to detect the beginning and ending of a swipe.
            // The beginning of a swipe has small circle because it is easy to control
            // the beginning of a swipe, so precision is important. The ending circle
            // is quite a bit larger to allow more liberal detection of a swipe since the
            // end of a swipe tends to be less precise.
            _startCollision = ShapeManager.AddCircle();
            _startCollision.AttachTo(_sprite, false);
            _startCollision.Radius = .3f * _sprite.Texture.Width / _sprite.PixelPerUnit();
            _startCollision.RelativeX = .7f * _sprite.ScaleX;
            _startCollision.Visible = false;

            _endCollision = ShapeManager.AddCircle();
            _endCollision.AttachTo(_sprite, false);
            _endCollision.Radius = .5f * _sprite.Texture.Width / _sprite.PixelPerUnit();
            _endCollision.RelativeX = -_sprite.ScaleX;
            _endCollision.Visible = false;

            // sloppy adjusting of the velcro hitbox.
            _collision.ScaleBy(1.0f, 1.0f);
            _collision.Visible = false;

            // if the drag leaves this box, the drag is cancelled
            _touchCollision = Polygon.CreateRectangle(_sprite.ScaleX * xScale, 
                _sprite.ScaleY * yScale);
            ShapeManager.AddPolygon(_touchCollision);
            _touchCollision.AttachTo(_sprite, false);
            _touchCollision.Visible = false;
            _touchCollision.ScaleBy(1.9f, 1.9f);
            //_touchCollision.RelativeX += _sprite.ScaleX / 2.3f;

            // The indicator that comes on screen if it is a tutorial level.
            SetTooltip("swipe");
            _tooltip.RelativeX = 0.0f;
            _tooltip.RelativeZ = 0.15f;
            _tooltip.RelativeY = 9.0f;
            _tooltip.RelativeRotationZ = -this.RotationZ;

            // initialize velcro opening sound.
            _openSound = FlatRedBallServices.Load<SoundEffect>(@"Content\Sound\velcro");

            _resetTime = 0.0f;

            _timeText = TextManager.AddText("0", GameProperties.CustomFont);
            _timeText.Alpha = 0.0f;
            _timeText.Scale = 1.0f;
            _timeText.Spacing = 1.0f;
            _timeText.SetColor(1.0f, 1.0f, 1.0f);
            _timeText.AttachTo(this, false);
            _timeText.RelativeZ = 0.5f;

            ResetGesture();

            TouchManager.AddDraggable(this);
            TouchManager.AddPullable(this);
        }

        #endregion

        #region Update
        public override void Activity(GameGesture zipGesture, double t)
        {
            Vector3 dragEndPoint = _lastDrag.End;
            if (!_touchCollision.IsPointInside(ref dragEndPoint))
            {
                ResetGesture();
            }

            // Terminates the animation at the end of it.
            if (_sprite.JustCycled)
            {
                _sprite.Animate = false;
                _sprite.CurrentFrameIndex = 9;
            }

            if (!_enabled && _openTime != 0)
            {
                // get the amount of time that has elapsed since last update
                _elapsedTime = t - _startTime;
                Countdown();
            }

            if (_tooltip.Visible)
            {
                PlayTooltip();
            }
        }

        public override void Collide(double t)
        {
            return;
        }

        #endregion

        #region Destroy
        public override void Destroy()
        {
            base.Destroy();

            ShapeManager.Remove(_startCollision);
            ShapeManager.Remove(_endCollision);
            ShapeManager.Remove(_touchCollision);

            TouchManager.RemoveDraggable(this);
            TouchManager.RemovePullable(this);

            TextManager.RemoveText(_timeText);
        }
        #endregion

        #region Private Methods

        #region Tooltip
        // Flashes the tap this indicator.
        protected override void PlayTooltip()
        {
            if (_tooltip.RelativeY > -4.0f)
            {
                _tooltip.RelativeAcceleration.Y = -35.0f;
            }
            else if (_tooltip.RelativeY < -4.0f)
            {
                _tooltip.RelativeVelocity.Y = 0.0f;
                _tooltip.RelativeAcceleration.Y = 0.0f;

                if (_resetTime <= 0)
                    _resetTime = TimeManager.CurrentTime;
                else
                {
                    if (TimeManager.CurrentTime - _resetTime > 1.0f)
                    {
                        _tooltip.RelativeY = 9.0f;
                        _resetTime = 0;
                    }
                }
            }
        }

        #endregion

        private void Countdown()
        {
            if (_elapsedTime >= _openTime)
            {
                _sprite.CurrentChainName = "closing";
                _sprite.CurrentFrameIndex = 0;
                _sprite.Animate = true;
                _openSound.PlaySound();
                _enabled = true;

                _timeText.Alpha = 1.0f;
                _timeText.DisplayText = "0";
                _timeText.AlphaRate = -1.0f;

                _elapsedTime = 0;
            }
            else
            {
                int displayTime = _openTime - (int)_elapsedTime;
                if (!_timeText.DisplayText.Equals(displayTime.ToString()))
                {
                    _timeText.Alpha = 1.0f;
                    _timeText.DisplayText = displayTime.ToString();
                    _timeText.AlphaRate = -1.0f;
                }
            }
        }

        #region Gesture Management

        private void ResetGesture()
        {
            _lastDrag = new GameGesture(GameGestureType.None, Vector3.Zero, Vector3.Zero, 0, -2);
        }

        #region Pull
        public bool WasPulled(GameGesture g)
        {
            Vector3 touchPoint = g.End;
            return (g.GameGestureType == GameGestureType.Pull
                 && g.Id == _lastDrag.Id
                 && _enabled);
        }

        public void OnPull(GameGesture g)
        {
            Vector3 touchPoint = g.End;
            // make sure the pull occurred in the right direction
            //if ((g.Start - _endCollision.Position).Length() > 
            //    (g.End - _endCollision.Position).Length())
            if (_sprite.CurrentFrameIndex > 0)
            {
                _sprite.CurrentChainName = "opening";
                _enabled = false;
                _tooltip.Visible = false;
                _sprite.Animate = true;
                _openSound.PlaySound();
            }
            else
            {
                ResetGesture();
            }
            
        }
        #endregion

        #region Drag
        public bool WasDragged(GameGesture g)
        {
            Vector3 touchPoint = g.End;
            return (g.GameGestureType == GameGestureType.Drag
                && _touchCollision.IsPointInside(ref touchPoint)
                && _enabled);
        }

        public bool OnDrag(GameGesture g)
        {
            Vector3 touchPoint = g.End;
            if (g.Id != TouchManager.ZipperDrag.Id
                && _startCollision.IsPointInside(ref touchPoint))
            {
                _lastDrag = g;
                _sprite.CurrentChainName = "opening";

                MoveVelcro(g);

                return true;
            }
            else if (g.Id == _lastDrag.Id)
            {
                MoveVelcro(g);

                return true;
            }

            

            return false;
        }

        private void MoveVelcro(GameGesture g)
        {
            float progress = (_endCollision.Position - g.End).Length();
            float total = (_endCollision.Position - _startCollision.Position).Length();
            int ratio = (int)(((total - progress) / total) * 10);

            if (ratio > -1 && ratio < 10)
            {
                _sprite.CurrentFrameIndex = ratio;
            }
        }

        #endregion

        #endregion

        #endregion

        #endregion


    }
}

